#include "NetModule.h"
#include "Net.h"
#include "Protocol/Protocol.h"

FragrantGrass::NetModule::NetModule(IPluginManager* p)
{
	m_pPluginManager = p;
	m_kNetMessageHandles.clear();
	m_kNetEventCallbackHandles.clear();
	m_kNetMessageCallbackHandles.clear();
	m_LastTime = GetPluginManager()->GetNowTime();
	m_pkNet = NULL;
}

FragrantGrass::NetModule::~NetModule()
{
	m_kNetMessageHandles.clear();
	m_kNetEventCallbackHandles.clear();
	m_kNetMessageCallbackHandles.clear();
	if (m_pkNet)
	{
		m_pkNet->destroy();
		delete m_pkNet;
		m_pkNet = NULL;
	}
}

bool FragrantGrass::NetModule::Init()
{
	m_pkLogModule = m_pPluginManager->FindModule<ILogModule>();

	//Protocol::MsgBase xMsg;
	//auto dp = xMsg.GetDescriptor();
	//if (NULL != dp)
	//{
	//	m_pkLogModule->LogDebug("[DP] SUcceed", __FUNCTION__, __LINE__);
	//}
	//Protocol::ServerConfigTable xG;
	//auto xp = xG.GetDescriptor();
	//if (NULL != xp)
	//{
	//	m_pkLogModule->LogDebug("[XP] SUcceed", __FUNCTION__, __LINE__);
	//}

	return true;
}

bool FragrantGrass::NetModule::AfterInit()
{
	return true;
}

int FragrantGrass::NetModule::init_as_client(const char* ip, unsigned short port)
{
	m_pkNet = new Net(this, &NetModule::handle_net_msg, &NetModule::handle_net_event);
	expand_buffer_size(4096);
	return m_pkNet->init_as_client(ip, port);
}

int FragrantGrass::NetModule::init_as_server(unsigned int max_client_cnt, unsigned short port, int cpu_count)
{
	m_pkNet = new Net(this, &NetModule::handle_net_msg, &NetModule::handle_net_event);
	expand_buffer_size(4096);
	return m_pkNet->init_as_server(max_client_cnt, port, cpu_count);
}

int FragrantGrass::NetModule::expand_buffer_size(unsigned int size/* = 1024 * 1024 * 20*/)
{
	if (m_pkNet)
	{
		return m_pkNet->expand_buffer_size(size);
	}
	return 0;
}

bool FragrantGrass::NetModule::register_net_message_handler(int id, const NET_MESSAGE_HANDLER_FUNCTOR_PTR& cb)
{
	std::list<NET_MESSAGE_HANDLER_FUNCTOR_PTR>& msg_handle_list = m_kNetMessageHandles[id];

	//NetMessageHandleMap::iterator it = m_kNetMessageHandles.find(id);
	//if (it == m_kNetMessageHandles.end())
	//{
	//	NetMessageHandleList msg_handle_list;
	//	msg_handle_list.push_back(cb);
	//	m_kNetMessageHandles.insert(NetMessageHandleMap::value_type(id, msg_handle_list));
	//	return true;
	//}
	//NetMessageHandleList& msg_handle_list = it->second;

	msg_handle_list.push_back(cb);

	return true;
}

bool FragrantGrass::NetModule::register_net_message_handler(const NET_MESSAGE_HANDLER_FUNCTOR_PTR& cb)
{
	if (cb.get())
	{
		m_kNetMessageCallbackHandles.push_back(cb);
	}
	return true;
}

bool FragrantGrass::NetModule::register_net_event_handler(const NET_EVENT_HANDLER_FUNCTOR_PTR& cb)
{
	if (cb.get())
	{
		m_kNetEventCallbackHandles.push_back(cb);
	}
	return true;
}

bool FragrantGrass::NetModule::send_msg_with_out_head(int16_t id, const std::string& msg, SOCK fd)
{
	if (!m_pkNet || !m_pkNet->send_msg_with_out_head(id, msg.data(), (uint32_t)msg.length(), fd))
	{
		std::ostringstream stream;
		if (!m_pkNet)
			stream << "send_msg_with_out_head failed m_pkNet is null,fd = %ld msgid =" << id << std::endl;
		else
			stream << "send_msg_with_out_head failed fd = " << fd << "msgid = " << id << std::endl;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);
		return false;
	}

	return true;
}

bool FragrantGrass::NetModule::send_msg_with_out_head(const uint16_t nMsgID, const std::string& xData, const SOCK nSockIndex, const GUID id)
{
	Protocol::MsgBase xMsg;
	xMsg.set_msg_data(xData.data(), xData.length());

	Protocol::Ident* pPlayerID = xMsg.mutable_player_id();
	*pPlayerID = FGToPB(id);

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPB Message to  " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	return send_msg_with_out_head(nMsgID, strMsg, nSockIndex);
}

bool FragrantGrass::NetModule::send_msg_to_all_client_with_out_head(int16_t id, const std::string& msg)
{
	if (!m_pkNet || !m_pkNet->send_msg_to_all_client_with_out_head(id, msg.data(), (uint32_t)msg.length()))
	{
		std::ostringstream stream;
		if (!m_pkNet)
			stream << "send_msg_with_out_head send_msg_to_all_client_with_out_head m_pkNet is null,msgid = " << id << std::endl;
		else
			stream << "send_msg_to_all_client_with_out_head failed msgid = " << id << std::endl;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);
		return false;
	}

	return true;
}

bool FragrantGrass::NetModule::send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex)
{
	Protocol::MsgBase xMsg;
	if (!xData.SerializeToString(xMsg.mutable_msg_data()))
	{
		std::ostringstream stream;
		stream << " SendMsgPB Message to  " << nSockIndex;
		stream << " Failed For Serialize of MsgData, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	Protocol::Ident* pPlayerID = xMsg.mutable_player_id();
	*pPlayerID = FGToPB(GUID());

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPB Message to  " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	send_msg_with_out_head(nMsgID, strMsg, nSockIndex);

	return true;
}

bool FragrantGrass::NetModule::send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex, const GUID id)
{
	Protocol::MsgBase xMsg;
	if (!xData.SerializeToString(xMsg.mutable_msg_data()))
	{
		std::ostringstream stream;
		stream << " SendMsgPB Message to  " << nSockIndex;
		stream << " Failed For Serialize of MsgData, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	Protocol::Ident* pPlayerID = xMsg.mutable_player_id();
	*pPlayerID = FGToPB(id);

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPB Message to  " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	return send_msg_with_out_head(nMsgID, strMsg, nSockIndex);
}

bool FragrantGrass::NetModule::send_protobuf_message(const uint16_t nMsgID, const google::protobuf::Message& xData, const SOCK nSockIndex, const std::vector<GUID>* pClientIDList)
{
	if (!m_pkNet)
	{
		std::ostringstream stream;
		stream << " m_pNet SendMsgPB faailed fd " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	Protocol::MsgBase xMsg;
	if (!xData.SerializeToString(xMsg.mutable_msg_data()))
	{
		std::ostringstream stream;
		stream << " SendMsgPB faailed fd " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	Protocol::Ident* pPlayerID = xMsg.mutable_player_id();
	*pPlayerID = FGToPB(GUID());
	if (pClientIDList)
	{
		for (int i = 0; i < pClientIDList->size(); ++i)
		{
			const GUID& ClientID = (*pClientIDList)[i];

			Protocol::Ident* pData = xMsg.add_player_client_list();
			if (pData)
			{
				*pData = FGToPB(ClientID);
			}
		}
	}

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPB faailed fd " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	return send_msg_with_out_head(nMsgID, strMsg, nSockIndex);
}

bool FragrantGrass::NetModule::send_protobuf_message(const uint16_t nMsgID, const std::string& strData, const SOCK nSockIndex, const std::vector<GUID>* pClientIDList)
{
	if (!m_pkNet)
	{
		std::ostringstream stream;
		stream << " SendMsgPB NULL Of Net faailed fd " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	Protocol::MsgBase xMsg;
	xMsg.set_msg_data(strData.data(), strData.length());

	Protocol::Ident* pPlayerID = xMsg.mutable_player_id();
	*pPlayerID = FGToPB(GUID());
	if (pClientIDList)
	{
		for (int i = 0; i < pClientIDList->size(); ++i)
		{
			const GUID& ClientID = (*pClientIDList)[i];

			Protocol::Ident* pData = xMsg.add_player_client_list();
			if (pData)
			{
				*pData = FGToPB(ClientID);
			}
		}
	}

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPB failed fd " << nSockIndex;
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	return send_msg_with_out_head(nMsgID, strMsg, nSockIndex);
}

bool FragrantGrass::NetModule::send_protobuf_message_to_all_clients(const uint16_t nMsgID, const google::protobuf::Message& xData)
{
	Protocol::MsgBase xMsg;
	if (!xData.SerializeToString(xMsg.mutable_msg_data()))
	{
		std::ostringstream stream;
		stream << " SendMsgPBToAllClient";
		stream << " Failed For Serialize of MsgData, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	std::string strMsg;
	if (!xMsg.SerializeToString(&strMsg))
	{
		std::ostringstream stream;
		stream << " SendMsgPBToAllClient";
		stream << " Failed For Serialize of MsgBase, MessageID " << nMsgID;
		m_pkLogModule->LogError(stream, __FUNCTION__, __LINE__);

		return false;
	}

	return send_msg_to_all_client_with_out_head(nMsgID, strMsg);
}

bool FragrantGrass::NetModule::Execute()
{
	if (!m_pkNet)
	{
		return false;
	}

	heart_beat();

	return m_pkNet->execute();
}

void FragrantGrass::NetModule::heart_beat()
{
	if (!m_pkNet)
	{
		return;
	}

	if (m_pkNet->run_as_server())
	{
		return;
	}

	if (m_LastTime + 10 > GetPluginManager()->GetNowTime())
	{
		return;
	}

	m_LastTime = GetPluginManager()->GetNowTime();

	Protocol::HeartBeat xMsg;
	xMsg.set_count(0);

	send_protobuf_message(Protocol::EGameMsgID::EGMI_STS_HEART_BEAT, xMsg, 0);
}

FragrantGrass::INet* FragrantGrass::NetModule::getNet()
{
	return m_pkNet;
}

void FragrantGrass::NetModule::handle_net_msg(SOCK fd, int id, const char* msg, uint32_t len)
{
	NetMessageHandleMap::iterator it = m_kNetMessageHandles.find(id);
	std::list<NET_MESSAGE_HANDLER_FUNCTOR_PTR>& lists = (it == m_kNetMessageHandles.end()) ? m_kNetMessageCallbackHandles :it->second;
	for (std::list<NET_MESSAGE_HANDLER_FUNCTOR_PTR>::iterator handler = lists.begin(); handler != lists.end(); ++handler)
	{
		NET_MESSAGE_HANDLER_FUNCTOR_PTR& func_ptr = *handler;
		NET_MESSAGE_HANDLER_FUNCTOR* pFunc = func_ptr.get();
		if (NULL != pFunc)
		{
			try
			{
				(*pFunc)(fd, id, msg, len);
			}
			catch (const std::exception & e)
			{
# if __WORDSIZE == 64
				fprintf(stderr, "[NetModule::handle_net_msg]:fd = %ld id = %d err = %s\n", fd, id, e.what());
# else
				fprintf(stderr, "[NetModule::handle_net_msg]:fd = %lld id = %d err = %s\n", fd, id, e.what());
# endif
			}
		}
	}
}

void FragrantGrass::NetModule::handle_net_event(SOCK fd, FG_NET_EVENT events, INet* net)
{
	std::list<NET_EVENT_HANDLER_FUNCTOR_PTR>& lists = m_kNetEventCallbackHandles;
	for (std::list<NET_EVENT_HANDLER_FUNCTOR_PTR>::iterator handler = lists.begin(); handler != lists.end(); ++handler)
	{
		NET_EVENT_HANDLER_FUNCTOR_PTR& func_ptr = *handler;
		NET_EVENT_HANDLER_FUNCTOR* pFunc = func_ptr.get();
		if (NULL != pFunc)
		{
			try
			{
				(*pFunc)(fd, events, net);
			}
			catch (const std::exception& e)
			{
# if __WORDSIZE == 64
				fprintf(stderr, "[NetModule::handle_net_event]:fd = %ld id = %d err = %s\n", fd, events, e.what());
# else
				fprintf(stderr, "[NetModule::handle_net_event]:fd = %lld id = %d err = %s\n", fd, events, e.what());
# endif
			}
		}
	}
}